package utils

import (
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	message "learningProject/shangguigu/common"
	"net"
)

// 将这些方法关联到结构体中
type Transfer struct {
	Conn net.Conn
	Buf  [8096]byte
}

// 处理客户端读到的数据，并返回结果
func (this *Transfer) ReadPkg() (mes message.Message, err error) {
	//buf := make([]byte,8096)
	fmt.Println("读取客户端发送的数据")

	// conn.Read只有在conn没有被关闭的情况下才会阻塞在这里
	// 客户端和服务器任意一端关闭conn，这里就不会阻塞
	_, err = this.Conn.Read(this.Buf[:4]) // 先只读4个字节，因为客户端发来的表示数据长度的数据是4字节
	if err != nil {
		//err = errors.New("conn.Read err")
		return
	}
	fmt.Println("读到的buf=", this.Buf[:4])

	// 将buf[:4]转成uint32
	var pkgLen uint32
	pkgLen = binary.BigEndian.Uint32(this.Buf[0:4])

	//根据pkglen读取消息内容
	n, err := this.Conn.Read(this.Buf[:pkgLen]) // 这句话意思是从conn里读取pkgLen个字节，并追加到buf里
	//conn.Read读一次后buf里就没东西了
	if n != int(pkgLen) || err != nil {
		err = errors.New("conn.Read 消息本体 err")
		return
	}

	// 先反序列化成Message类型
	err = json.Unmarshal(this.Buf[:pkgLen], &mes) // 注意mes前要加&  把buf反序列化后放到mes里
	if err != nil {
		err = errors.New("json.Unmarshal err")
		return
	}

	return // go 直接写return会帮我们将所有的返回值返回

}

// 将数据发回客户端
func (this *Transfer) WritePkg(data []byte) (err error) {
	//发送data的长度和内容给对方
	//注意  conn.Write必须传入byte切片
	var pkgLen uint32
	pkgLen = uint32(len(data))
	//var buf [4]byte  // uint32是4个字节，所以这里是[4]byte
	binary.BigEndian.PutUint32(this.Buf[0:4], pkgLen) //将pkgLen转为byte切片
	// 发送长度
	n, err := this.Conn.Write(this.Buf[:4]) //n表示发送了几字节的数据
	if n != 4 || err != nil {
		fmt.Println("conn.Write(buf) err", err)
		return
	}
	fmt.Printf("服务端成功发送数据长度=%d\n", len(data))

	// 发送消息本身
	_, err = this.Conn.Write(data) //n表示发送了几字节的数据
	if err != nil {
		fmt.Println("conn.Write(data) err", err)
		return
	}
	fmt.Printf("服务端成功发送数据本身\n")
	return
}
